package com.cy.sca.api.aspect;

import com.cy.sca.api.feign.RemoteNoticeService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Aspect //此注解描述的类为切面类，其内部可以定义切入点表达式和通知方法
@Component //此注解描述类是要交给spring管理
public class LogAspect {
    //构建日志规范对象(这里用到了门面模式)
    private static final Logger log=
            LoggerFactory.getLogger(LogAspect.class);
    /**
     * 基于@Pointcut注解定义切入点
     * 这里表示由RequiredLog注解描述的方法为一个切入点方法
     * @annotation注解方式的表达式为细粒度的切入点表达式，可以精确具体方法
     * */
    @Pointcut("@annotation(com.cy.sca.api.annotation.RequiredLog)")
    public void doLog(){}//承载切入点表达式的定义，方法不写任何内容
    /**
     * 通知方法(@Around):可以在此通知方法内部手动调用目标方法
     * @param jp 连接点(封装你要调用的目标方法信息)，ProceedingJoinPoint这个
     *           类型的切入点只能应用于@Around通知。其它通知方法只能使用
     *           JoinPoint类型的连接点
     * @return 目标方法的返回结果
     * @throws Throwable
     */
    //@Around("@annotation(com.cy.sca.api.annotation.RequiredLog)")
    @Around("doLog()")
    public Object doAround(ProceedingJoinPoint jp)throws Throwable{
        //构建一个map对象，基于此对象存储获取到的操作日志，后续也可以是一个pojo对象
        Map<String,Object> logInfo=new HashMap<>();
        //获取目标类的类全名
        String targetClassName = jp.getTarget().getClass().getName();
        logInfo.put("targetClass",targetClassName);
        //获取目标方法名
        Signature signature=jp.getSignature();//方法签名，包含方法信息
        String methodName=signature.getName();
        logInfo.put("targetMethod","methodName");
        //获取执行方法时你传入的参数
        Object args[]=jp.getArgs();
        //基于第三方jackson实现将对象转换json串的操作
        String jsonArgs=new ObjectMapper().writeValueAsString(args);
        logInfo.put("requestParams", jsonArgs);
        long t1=System.currentTimeMillis();
        System.out.println("start:"+t1);
        try {
            Object result = jp.proceed();//执行切面链(切面链中的最终的执行方法为我们的目标方法)
            long t2 = System.currentTimeMillis();
            long time=t2-t1;
            logInfo.put("status",1);//1表示ok
            logInfo.put("usedTime", time);
            System.out.println("after:" + t2);
            return result;
        }catch(Throwable e){
            long t3= System.currentTimeMillis();
            long time=t3-t1;
            logInfo.put("status",0);//0表示exception,error
            logInfo.put("usedTime", time);
            logInfo.put("errorMsg", e.getMessage());
            System.out.println("error:"+t3);
            throw e;
        }finally{
            log.info("operation log {} ",logInfo.toString());
            //将logInfo传递给用于进行日志记录或发送的服务。
            remoteNoticeService.doLoginfo(logInfo);
        }

    }
    @Autowired
    private RemoteNoticeService remoteNoticeService;
}
